package math.visitors;

import math.BooleanEquality;
import math.Xor;
import math.ArithmeticError;
import math.LogicalBooleanVariable;
import math.Expression;
import math.Rater;
import math.Not;
import math.Add;
import math.And;
import math.BooleanConstant;
import math.BooleanVariable;
import math.Cos;
import math.Evaluation;
import math.Exp;
import math.IntegerConstant;
import math.Ln;
import math.LogicalArithmeticVariable;
import math.Mult;
import math.Negation;
import math.NumericLogicalVariable;
import math.Or;
import math.PI;
import math.Pow;
import math.Sin;
import math.Variable;
import math.ExpressionVisitor;

public class CountMembersVisitor implements ExpressionVisitor<Integer>, Rater{

  @Override
  public Integer visitAnd(And and) {
    return Integer.valueOf(and.getArg1().accept(this).intValue() + and.getArg2().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitBooleanConstant(BooleanConstant booleanConstant) {
    return Integer.valueOf(1);
  }

  @Override
  public Integer visitBooleanVariable(BooleanVariable booleanVariable) {
    return Integer.valueOf(1);
  }

  @Override
  public Integer visitOr(Or or) {
    return Integer.valueOf(or.getArg1().accept(this).intValue() + or.getArg2().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitXor(Xor xor) {
    return Integer.valueOf(xor.getArg1().accept(this).intValue() + xor.getArg2().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitAdd(Add add) {
    return Integer.valueOf(add.getAddend1().accept(this).intValue() + add.getAddend2().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitCos(Cos cos) {
    return Integer.valueOf(cos.getArgument().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitEvaluation(Evaluation evaluation) {
    return evaluation.countMembers();
  }

  @Override
  public Integer visitExp(Exp exp) {
    return Integer.valueOf(exp.getArgument().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitIntegerConstant(IntegerConstant value) {
    return Integer.valueOf(1);
  }

  @Override
  public Integer visitLn(Ln ln) {
    return Integer.valueOf(ln.getArgument().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitLogicalArithmeticVariable(LogicalArithmeticVariable logicalVariable) {
    return Integer.valueOf(1);
  }
  
  @Override
  public Integer visitLogicalBooleanVariable(LogicalBooleanVariable logicalVariable) {
    return Integer.valueOf(1);
  }

  @Override
  public Integer visitMult(Mult mult) {
    return Integer.valueOf(mult.getFactor1().accept(this).intValue() + mult.getFactor2().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitNegation(Negation negation) {
    return Integer.valueOf(negation.getArgument().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitNumericalLogicalVariable(
      NumericLogicalVariable numericLogicalVariable) {
    return Integer.valueOf(1);
  }

  @Override
  public Integer visitPI(PI pi) {
    return Integer.valueOf(1);
  }

  @Override
  public Integer visitPow(Pow pow) {
    return Integer.valueOf(pow.getBase().accept(this).intValue() + pow.getExponent().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitSin(Sin sin) {
    return Integer.valueOf(sin.getArgument().accept(this).intValue() + 1);
  }

  @Override
  public Integer visitVariable(Variable var) {
    return Integer.valueOf(1);
  }

  @Override
  public Integer visitNot(Not not) {
    return Integer.valueOf(not.getArgument().accept(this).intValue() + 1);
  }

  @Override
  public int rate(Expression exp) {
    return exp.accept(this);
  }

  @Override
  public Integer visitArithmeticError(ArithmeticError arithmeticError) {
    return Integer.valueOf(0);
  }

  @Override
  public Integer visitBooleanEquality(BooleanEquality booleanEquality) {
    return Integer.valueOf(booleanEquality.getArg1().accept(this).intValue() + booleanEquality.getArg2().accept(this).intValue() + 1);
  }
}